Iterators & generators¶
Iterators are used when we need more control in the iteration process. Iterators can enable lazy evaluation, which means that the elements are generated or fetched only when needed, rather than loading the entire sequence into memory upfront. This is particularly useful when dealing with large or infinite sequences. Loops, on the other hand, typically require the entire sequence to be available in memory or predefined before execution.
Below is an example of a predefined iterator in python
In [1]:
arr = [1,4,2,5,3,-2,-1,6]
my_iterator = iter(arr)
# next(it1) and it1.__next__() does the same thing
print(next(my_iterator),end = " ") # prints 1
print(my_iterator.__next__(),end = " ") # prints 4
# prints the rest of the numbers
for i in my_iterator:
print(i,end = " ")
print()
1 4 2 5 3 -2 -1 6
Below is an example of a custom made iterator¶
In [2]:
# Creating a custom iterator for a list
class myIterator:
def __init__(self, iterable, someFunction = lambda x:x):
self.iterable = iterable
self.index = 0
self.function = someFunction
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.iterable):
raise StopIteration
value = self.iterable[self.index]
self.index += 1
return self.function(value)
# Using custom iterator
my_iterator2 = myIterator(arr)
my_iterator3 = myIterator(arr,lambda x:2*x+1)
for item in my_iterator2:
print(item, end = " ")
print()
for item in my_iterator3:
print(item, end = " ")
print()
1 4 2 5 3 -2 -1 6 3 9 5 11 7 -3 -1 13
Generators in python are functions that return iterators. Example given below¶
In [3]:
def myGenerator(n, someFunc = lambda x:x):
x = 0
while x <= n:
x += 1
yield someFunc(x)
Driver code¶
In [4]:
if __name__ == "__main__":
arr1 = myGenerator(5)
arr2 = myGenerator(5, lambda x:x*x)
for i in arr1:
print(i, end = " ")
print()
for i in arr2:
print(i, end = " ")
print()
1 2 3 4 5 6 1 4 9 16 25 36